package org.linlinjava.litemall.wx.service;

import cn.hutool.core.collection.CollUtil;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult;
import com.github.binarywang.wxpay.bean.order.WxPayMwebOrderResult;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.bean.result.BaseWxPayResult;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.wxpay.sdk.WXPay;
import com.github.wxpay.sdk.WXPayUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.linlinjava.litemall.core.exception.BusinessException;
import org.linlinjava.litemall.core.exception.ResultError;
import org.linlinjava.litemall.core.express.ExpressService;
import org.linlinjava.litemall.core.express.dao.ExpressInfoVO;
import org.linlinjava.litemall.core.express.dao.TracesVO;
import org.linlinjava.litemall.core.task.TaskService;
import org.linlinjava.litemall.core.util.*;
import org.linlinjava.litemall.db.dao.LitemallInvoiceMapper;
import org.linlinjava.litemall.db.domain.*;
import org.linlinjava.litemall.db.service.*;
import org.linlinjava.litemall.db.util.CouponUserConstant;
import org.linlinjava.litemall.db.util.DateUtil;
import org.linlinjava.litemall.db.util.OrderHandleOption;
import org.linlinjava.litemall.db.util.OrderUtil;
import org.linlinjava.litemall.wx.config.OurWxPayConfig;
import org.linlinjava.litemall.wx.dto.SubmitOrderDTO;
import org.linlinjava.litemall.wx.task.OrderUnpaidTask;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.groupingBy;
import static org.linlinjava.litemall.wx.util.WxResponseCode.*;

/**
 * 订单服务
 *
 * <p>
 * 订单状态：
 * 101 订单生成，未支付；102，下单后未支付用户取消；103，下单后未支付超时系统自动取消
 * 201 支付完成，商家未发货；202，订单生产，已付款未发货，但是退款取消；
 * 301 商家发货，用户未确认；
 * 401 用户确认收货； 402 用户没有确认收货超过一定时间，系统自动确认收货；
 *
 * <p>
 * 用户操作：
 * 当101用户未付款时，此时用户可以进行的操作是取消订单，或者付款操作
 * 当201支付完成而商家未发货时，此时用户可以取消订单并申请退款
 * 当301商家已发货时，此时用户可以有确认收货的操作
 * 当401用户确认收货以后，此时用户可以进行的操作是删除订单，评价商品，申请售后，或者再次购买
 * 当402系统自动确认收货以后，此时用户可以删除订单，评价商品，申请售后，或者再次购买
 */
@Service
@Slf4j
public class WxOrderService {
    private final Log logger = LogFactory.getLog(WxOrderService.class);

    @Resource
    private UserService userService;
    @Resource
    private OrderService orderService;
    @Resource
    private OrderGoodsService orderGoodsService;
    @Resource
    private GoodsService goodsService;
    @Resource
    private AddressService addressService;
    @Resource
    private CartService cartService;
    @Resource
    private WxPayService wxPayService;
    @Resource
    private ExpressService expressService;
    @Resource
    private CommentService commentService;
    @Resource
    private CouponUserService couponUserService;
    @Resource
    private TaskService taskService;
    @Resource
    private AftersaleService aftersaleService;
    @Resource
    private LitemallInvoiceMapper invoiceMapper;

    private String notifyUrl = "http://1.13.24.189:8080/wx/order/pay-notify";

    /**
     * 订单列表
     *
     * @param userId   用户ID
     * @param showType 订单信息：
     * @param page     分页页数
     * @param limit     分页大小
     * @return 订单列表
     */
    public Object list(Integer userId, Integer showType, Integer page, Integer limit, String sort, String order) {
        if (userId == null) {
            return ResponseUtil.unlogin();
        }

        List<Short> orderStatus = OrderUtil.orderStatus(showType);
        List<LitemallOrder> orderList = orderService.queryByOrderStatus(userId, orderStatus, page, limit, sort, order);

        List<Map<String, Object>> orderVoList = new ArrayList<>(orderList.size());
        for (LitemallOrder o : orderList) {
            Map<String, Object> orderVo = new HashMap<>();
            orderVo.put("id", o.getId());
            orderVo.put("orderSn", o.getOrderSn());
            orderVo.put("actualPrice", o.getActualPrice());
            orderVo.put("orderStatusText", OrderUtil.orderStatusText(o));
            orderVo.put("orderStatus", o.getOrderStatus());
            orderVo.put("createTime", o.getAddTime());
            orderVo.put("reason", o.getRefundContent());
            orderVo.put("shipType", o.getShipType());

            List<LitemallOrderGoods> orderGoodsList = orderGoodsService.queryByOid(o.getId());
            List<Map<String, Object>> orderGoodsVoList = new ArrayList<>(orderGoodsList.size());
            for (LitemallOrderGoods orderGoods : orderGoodsList) {
                Map<String, Object> orderGoodsVo = new HashMap<>();
                orderGoodsVo.put("id", orderGoods.getId());
                orderGoodsVo.put("goodsName", orderGoods.getGoodsName());
                orderGoodsVo.put("number", orderGoods.getNumber());
                orderGoodsVo.put("picUrl", orderGoods.getPicUrl());
                orderGoodsVo.put("price",orderGoods.getPrice());
                orderGoodsVoList.add(orderGoodsVo);
            }
            orderVo.put("orderNum", orderGoodsList.size());
            orderVo.put("goodsList", orderGoodsVoList);

            orderVoList.add(orderVo);
        }

        return ResponseUtil.okList(orderVoList, orderList);
    }

    /**
     * 获取物流信息
     * @param orderId 订单id
     * @return 物流信息
     */
    public JsonResponse<ExpressInfoVO> expressInfo(Integer orderId) {
        Map<String, Object> result = new HashMap<>();
        LitemallOrder order = orderService.findById(orderId);
        // 订单状态为已发货且物流信息不为空
        //"YTO", "800669400640887922"
        ExpressInfoVO ei = null;
        if (order.getOrderStatus().equals(OrderUtil.STATUS_WAIT_ACCEPT)) {
            ei = expressService.getExpressInfo(order.getShipChannel(), order.getShipSn(), order.getMobile());
            if(ei == null){
                result.put("expressInfo", new ArrayList<>());
            }
            else {
                List<TracesVO> collect = ei.getTraces().stream().sorted(Comparator.comparing(TracesVO::getTime).reversed()).collect(Collectors.toList());
                ei.setTraces(collect);
                result.put("expressInfo", ei);
            }
        }
        else{
            result.put("expressInfo", new ArrayList<>());
        }
        return JsonResponse.ok(ei);
    }

    /**
     * 订单详情
     *
     * @param userId  用户ID
     * @param orderId 订单ID
     * @return 订单详情
     */
    public Object detail(Integer userId, Integer orderId) {
        if (userId == null) {
            return ResponseUtil.unlogin();
        }

        // 订单信息
        LitemallOrder order = orderService.findById(userId, orderId);
        if (null == order) {
            return ResponseUtil.fail(ORDER_UNKNOWN, "订单不存在");
        }
        if (!order.getUserId().equals(userId)) {
            return ResponseUtil.fail(ORDER_INVALID, "不是当前用户的订单");
        }
        Map<String, Object> orderVo = new HashMap<String, Object>();
        orderVo.put("id", order.getId());
        orderVo.put("orderSn", order.getOrderSn());
        orderVo.put("message", order.getMessage());
        orderVo.put("addTime", order.getAddTime());
        orderVo.put("consignee", order.getConsignee());
        orderVo.put("mobile", order.getMobile());
        orderVo.put("address", order.getAddress());
        orderVo.put("addressId", order.getAddressId());
        orderVo.put("goodsPrice", order.getGoodsPrice());
        orderVo.put("freightPrice", order.getFreightPrice());
        orderVo.put("actualPrice", order.getActualPrice());
        orderVo.put("orderStatusText", OrderUtil.orderStatusText(order));
        orderVo.put("orderStatus", order.getOrderStatus());
//        orderVo.put("handleOption", OrderUtil.build(order));
        orderVo.put("expCode", order.getShipChannel());
        orderVo.put("expName", expressService.getVendorName(order.getShipChannel()));
        orderVo.put("expNo", order.getShipSn());
        orderVo.put("reason", order.getRefundContent());
        orderVo.put("shipTime", order.getShipTime());
        orderVo.put("shipType", order.getShipType());

        List<LitemallOrderGoods> orderGoodsList = orderGoodsService.queryByOid(order.getId());
        int totalNum = 0;
        for (int i = 0; i < orderGoodsList.size(); i++) {
            totalNum = orderGoodsList.get(i).getNumber() + totalNum;
        }
        orderVo.put("totalNum", totalNum);
        Map<String, Object> result = new HashMap<>();
        result.put("orderInfo", orderVo);
        result.put("orderGoods", orderGoodsList);

        // 订单状态为已发货且物流信息不为空
        //"YTO", "800669400640887922"
        if (order.getOrderStatus().equals(OrderUtil.STATUS_WAIT_ACCEPT)) {
            ExpressInfoVO ei = expressService.getExpressInfo(order.getShipChannel(), order.getShipSn(), order.getMobile());
            if(ei == null){
                result.put("expressInfo", new ArrayList<>());
            }
            else {
                result.put("expressInfo", ei);
            }
        }
        else{
            result.put("expressInfo", new ArrayList<>());
        }

        return ResponseUtil.ok(result);

    }

    /**
     * 提交订单
     * <p>
     * 1. 创建订单表项和订单商品表项;
     * 2. 购物车清空;
     * 3. 优惠券设置已用;
     * 4. 商品货品库存减少;
     * 5. 如果是团购商品，则创建团购活动表项。
     *
     * @param submitOrderDTO   订单信息，{ cartId：xxx, addressId: xxx, couponId: xxx, message: xxx, grouponRulesId: xxx,  grouponLinkId: xxx}
     * @return 提交订单操作结果
     */
    @Transactional
    public JsonResponse submit(SubmitOrderDTO submitOrderDTO) {
        if (submitOrderDTO == null) {
            throw  BusinessException.create("订单对象不能为空");
        }
        Integer userId = submitOrderDTO.getUserId();
        List<Integer> cartIds = submitOrderDTO.getCartIds();
        Integer addressId = submitOrderDTO.getAddressId();
        String message = submitOrderDTO.getMessage();

        //

        // 收货地址
        LitemallAddress checkedAddress = addressService.query(userId, addressId);
        if (checkedAddress == null) {
            throw  BusinessException.create("无法获取到收货地址");
        }

        // 货品价格
        BigDecimal checkedGoodsPrice = new BigDecimal(0);

        List<LitemallCart> checkedGoodsList = new ArrayList<>(cartIds.size());
        if (cartIds.size() == 0) {
            if (StringUtils.isEmpty(submitOrderDTO.getGoodsId()) || StringUtils.isEmpty(submitOrderDTO.getNum())) {
                throw  BusinessException.create("商品id或商品数量不能为空");
            }
            LitemallGoods goods = goodsService.findById(submitOrderDTO.getGoodsId());
            checkedGoodsPrice = checkedGoodsPrice.add(goods.getRetailPrice().multiply(new BigDecimal(submitOrderDTO.getNum())));
        } else {
            cartIds.forEach(cartId->{
                LitemallCart cart = cartService.findById(cartId);
                checkedGoodsList.add(cart);
            });
            if (checkedGoodsList.size() == 0) {
                throw  BusinessException.create("选择商品为空");
            }
            for (LitemallCart checkGoods : checkedGoodsList) {
                checkedGoodsPrice = checkedGoodsPrice.add(checkGoods.getPrice().multiply(new BigDecimal(checkGoods.getNumber())));
            }
        }

        // 根据订单商品总价计算运费，满足条件（例如88元）则免运费，否则需要支付运费（例如8元）；
//        BigDecimal freightPrice = new BigDecimal(0);
//        if (checkedGoodsPrice.compareTo(SystemConfig.getFreightLimit()) < 0) {
//            freightPrice = SystemConfig.getFreight();
//        }

        // 可以使用的其他钱，例如用户积分
        BigDecimal integralPrice = new BigDecimal(0);

        // 订单费用
        // TODO 加上运费
//        BigDecimal orderTotalPrice = checkedGoodsPrice.add(freightPrice).max(new BigDecimal(0));
        BigDecimal orderTotalPrice = checkedGoodsPrice;
        // 最终支付费用
        BigDecimal actualPrice = orderTotalPrice.subtract(integralPrice);



        Integer orderId;
        LitemallOrder order;
        // 订单
        order = new LitemallOrder();
        order.setUserId(userId);
        order.setOrderSn(orderService.generateOrderSn(userId));
        order.setOrderStatus(OrderUtil.STATUS_CREATE);
        order.setConsignee(checkedAddress.getName());
        order.setMobile(checkedAddress.getTel());
        order.setMessage(message);
        // 发票信息
        if (!Objects.isNull(submitOrderDTO.getOrderInvoiceDTO())) {
            LitemallInvoice invoice = CloneUtil.clone(submitOrderDTO.getOrderInvoiceDTO(), LitemallInvoice.class);
            invoiceMapper.insert(invoice);
            order.setInvoiceId(invoice.getId());
        }
        String detailedAddress = checkedAddress.getProvince() + checkedAddress.getCity() + checkedAddress.getCounty() + " " + checkedAddress.getAddressDetail();
        order.setAddress(detailedAddress);
        order.setAddressId(addressId);
        order.setGoodsPrice(checkedGoodsPrice);
//        order.setFreightPrice(freightPrice);
        order.setIntegralPrice(integralPrice);
        order.setOrderPrice(orderTotalPrice);
        order.setActualPrice(actualPrice);

        // 添加订单表项
        orderService.add(order);
        orderId = order.getId();

        // 添加订单商品表项
        for (LitemallCart cartGoods : checkedGoodsList) {
            // 订单商品
            addOrderGoods(cartGoods, orderId);
        }

        // 删除购物车里面的商品信息
        cartIds.forEach(cartId->{
            cartService.deleteById(cartId);
        });

        // 立即购买，不是从购物车过来
        if (CollUtil.isEmpty(cartIds)) {
            LitemallGoods goods = goodsService.findById(submitOrderDTO.getGoodsId());
            LitemallCart cart = new LitemallCart();
            cart.setGoodsId(goods.getId());
            cart.setGoodsSn(goods.getGoodsSn());
            cart.setGoodsName(goods.getName());
            cart.setPicUrl(goods.getPicUrl());
            cart.setPrice(goods.getRetailPrice());
            cart.setNumber((short)1);
            cart.setAddTime(LocalDateTime.now());
            addOrderGoods(cart, orderId);
            // 判断数量是否大于秒杀商品数量
            if (DateUtil.isBetween(goods.getStartTime(), goods.getEndTime())) {
                if (goods.getKillNumber() - goods.getInitialNumber() <= submitOrderDTO.getNum()) {
                    throw BusinessException.create(ResultError.STOCK_NOT_FULL,"库存不足");
                }
            }
            if (goods.getNumber() - submitOrderDTO.getNum() < 0) {
                throw BusinessException.create(ResultError.STOCK_NOT_FULL,"库存不足");
            }
        }

        // 商品货品数量减少
        for (LitemallCart checkGoods : checkedGoodsList) {
            LitemallGoods goods = goodsService.findById(checkGoods.getGoodsId());
            int remainNumber = goods.getNumber() - checkGoods.getNumber();
            // 判断数量是否大于秒杀商品数量
            if (!StringUtils.isEmpty(goods.getStartTime())) {
                if (goods.getKillNumber() - goods.getInitialNumber() < checkGoods.getNumber()) {
                    throw BusinessException.create(ResultError.STOCK_NOT_FULL,"您购买的秒杀商品["+goods.getName()+"]数量不足");
                }
            }
            if (remainNumber < 0) {
                throw BusinessException.create(ResultError.STOCK_NOT_FULL,"你购买的商品["+goods.getName()+"]数量不足");
            }
            // 减少秒杀商品库存
            if (DateUtil.isBetween(goods.getStartTime(), goods.getEndTime())) {
                // 减少秒杀商品库存数量
                if (goodsService.reduceKillStock(goods.getId(), checkGoods.getNumber()) == 0) {
                    throw BusinessException.create(ResultError.STOCK_NOT_FULL,"商品货品库存减少失败");
                }
            }
            // 减少商品库存数量
            if (goodsService.reduceStock(goods.getId(), checkGoods.getNumber()) == 0) {
                throw BusinessException.create(ResultError.STOCK_NOT_FULL,"商品货品库存减少失败");
            }

        }

        // 订单支付超期任务
        taskService.addTask(new OrderUnpaidTask(orderId));

        Map<String, Object> data = new HashMap<>();
        data.put("orderId", orderId);
        return JsonResponse.ok(data);
    }

    private void addOrderGoods(LitemallCart cartGoods, Integer orderId) {
        // 订单商品
        LitemallOrderGoods orderGoods = new LitemallOrderGoods();
        orderGoods.setOrderId(orderId);
        orderGoods.setGoodsId(cartGoods.getGoodsId());
        orderGoods.setGoodsSn(cartGoods.getGoodsSn());
        orderGoods.setGoodsName(cartGoods.getGoodsName());
        orderGoods.setPicUrl(cartGoods.getPicUrl());
        orderGoods.setPrice(cartGoods.getPrice());
        orderGoods.setNumber(cartGoods.getNumber());
        orderGoods.setAddTime(LocalDateTime.now());

        orderGoodsService.add(orderGoods);
    }

    /**
     * 立即购买
     * @param submitOrderDTO 提交订单信息
     * @return 是否成功
     */
    public JsonResponse buyNow(SubmitOrderDTO submitOrderDTO) {
        Integer userId = submitOrderDTO.getUserId();
        List<Integer> cartIds = submitOrderDTO.getCartIds();
        Integer addressId = submitOrderDTO.getAddressId();
        String message = submitOrderDTO.getMessage();

        // 收货地址
        LitemallAddress checkedAddress = addressService.query(userId, addressId);
        if (checkedAddress == null) {
            return JsonResponse.error("无法获取到收货地址");
        }

        // 货品价格
        List<LitemallCart> checkedGoodsList = new ArrayList<>(cartIds.size());
        cartIds.forEach(cartId->{
            LitemallCart cart = cartService.findById(cartId);
            checkedGoodsList.add(cart);
        });
        if (checkedGoodsList.size() == 0) {
            return JsonResponse.error("选择商品为空");
        }
        BigDecimal checkedGoodsPrice = new BigDecimal(0);
        for (LitemallCart checkGoods : checkedGoodsList) {
            checkedGoodsPrice = checkedGoodsPrice.add(checkGoods.getPrice().multiply(new BigDecimal(checkGoods.getNumber())));
        }

        // 根据订单商品总价计算运费，满足条件（例如88元）则免运费，否则需要支付运费（例如8元）；
//        BigDecimal freightPrice = new BigDecimal(0);
//        if (checkedGoodsPrice.compareTo(SystemConfig.getFreightLimit()) < 0) {
//            freightPrice = SystemConfig.getFreight();
//        }

        // 可以使用的其他钱，例如用户积分
        BigDecimal integralPrice = new BigDecimal(0);

        // 订单费用
        // TODO 加上运费
//        BigDecimal orderTotalPrice = checkedGoodsPrice.add(freightPrice).max(new BigDecimal(0));
        BigDecimal orderTotalPrice = checkedGoodsPrice;
        // 最终支付费用
        BigDecimal actualPrice = orderTotalPrice.subtract(integralPrice);

        Integer orderId;
        LitemallOrder order;
        // 订单
        order = new LitemallOrder();
        order.setUserId(userId);
        order.setOrderSn(orderService.generateOrderSn(userId));
        order.setOrderStatus(OrderUtil.STATUS_CREATE);
        order.setConsignee(checkedAddress.getName());
        order.setMobile(checkedAddress.getTel());
        order.setMessage(message);
        String detailedAddress = checkedAddress.getProvince() + checkedAddress.getCity() + checkedAddress.getCounty() + " " + checkedAddress.getAddressDetail();
        order.setAddress(detailedAddress);
        order.setAddressId(addressId);
        order.setGoodsPrice(checkedGoodsPrice);
        // TODO 运费的产生
//        order.setFreightPrice(freightPrice);
        order.setIntegralPrice(integralPrice);
        order.setOrderPrice(orderTotalPrice);
        order.setActualPrice(actualPrice);

        // 添加订单表项
        orderService.add(order);
        orderId = order.getId();

        // 添加订单商品表项
        for (LitemallCart cartGoods : checkedGoodsList) {
            // 订单商品
            LitemallOrderGoods orderGoods = new LitemallOrderGoods();
            orderGoods.setOrderId(order.getId());
            orderGoods.setGoodsId(cartGoods.getGoodsId());
            orderGoods.setGoodsSn(cartGoods.getGoodsSn());
            orderGoods.setGoodsName(cartGoods.getGoodsName());
            orderGoods.setPicUrl(cartGoods.getPicUrl());
            orderGoods.setPrice(cartGoods.getPrice());
            orderGoods.setNumber(cartGoods.getNumber());
            orderGoods.setAddTime(LocalDateTime.now());

            orderGoodsService.add(orderGoods);
        }

        // 删除购物车里面的商品信息
        cartIds.forEach(cartId->{
            cartService.deleteById(cartId);
        });

        // 商品货品数量减少
        for (LitemallCart checkGoods : checkedGoodsList) {
            LitemallGoods goods = goodsService.findById(checkGoods.getGoodsId());

            int remainNumber = goods.getNumber() - checkGoods.getNumber();
            if (remainNumber < 0) {
                throw new RuntimeException("下单的商品货品数量大于库存量");
            }
            if (goodsService.reduceStock(goods.getId(), checkGoods.getNumber()) == 0) {
                throw new RuntimeException("商品货品库存减少失败");
            }
        }

        // 订单支付超期任务
        taskService.addTask(new OrderUnpaidTask(orderId));

        Map<String, Object> data = new HashMap<>();
        data.put("orderId", orderId);
        return JsonResponse.ok(data);
    }

    /**
     * 取消订单
     * <p>
     * 1. 检测当前订单是否能够取消；
     * 2. 设置订单取消状态；
     * 3. 商品货品库存恢复；
     * 4. 返还优惠券；
     *
     * @param userId 用户ID
     * @param orderId   订单id，{ orderId：xxx }
     * @return 取消订单操作结果
     */
    @Transactional
    public JsonResponse cancel(Integer userId, Integer orderId) {

        LitemallOrder order = orderService.findById(userId, orderId);
        if (!order.getUserId().equals(userId)) {
            return JsonResponse.error("当前订单不是该用户的订单");
        }

        // 检测是否能够取消
        OrderHandleOption handleOption = OrderUtil.build(order);
        if (!handleOption.isCancel()) {
            return JsonResponse.error(ORDER_INVALID_OPERATION, "订单不能取消");
        }

        // 设置订单已取消状态
        order.setOrderStatus(OrderUtil.STATUS_CANCEL);
        order.setEndTime(LocalDateTime.now());
        if (orderService.updateWithOptimisticLocker(order) == 0) {
            throw new RuntimeException("更新数据已失效");
        }

        // 商品货品数量增加
        List<LitemallOrderGoods> orderGoodsList = orderGoodsService.queryByOid(orderId);
        for (LitemallOrderGoods orderGoods : orderGoodsList) {
            Short number = orderGoods.getNumber();
            LitemallGoods goods = goodsService.findById(orderGoods.getGoodsId());
            if (goodsService.addStock(goods.getId(), number) == 0) {
                throw new RuntimeException("商品货品库存增加失败");
            }
        }

        return JsonResponse.ok("取消订单成功");
    }

    /**
     * 付款订单的预支付会话标识
     * <p>
     * 1. 检测当前订单是否能够付款
     * 2. 微信商户平台返回支付订单ID
     * 3. 设置订单付款状态
     *
     * @param userId 用户ID
     * @param body   订单信息，{ orderId：xxx }
     * @return 支付订单ID
     */
    @Transactional
    public Object prepay(Integer userId, String body, HttpServletRequest request) {
        if (userId == null) {
            return ResponseUtil.unlogin();
        }
        Integer orderId = JacksonUtil.parseInteger(body, "orderId");
        if (orderId == null) {
            return ResponseUtil.badArgument();
        }

        LitemallOrder order = orderService.findById(userId, orderId);
        if (order == null) {
            return ResponseUtil.badArgumentValue();
        }
        if (!order.getUserId().equals(userId)) {
            return ResponseUtil.badArgumentValue();
        }

        // 检测是否能够取消
        OrderHandleOption handleOption = OrderUtil.build(order);
        if (!handleOption.isPay()) {
            return ResponseUtil.fail(ORDER_INVALID_OPERATION, "订单不能支付");
        }

        LitemallUser user = userService.findById(userId);
        String openid = user.getWeixinOpenid();
        if (openid == null) {
            return ResponseUtil.fail(AUTH_OPENID_UNACCESS, "订单不能支付");
        }
        WxPayMpOrderResult result = null;
        try {
            WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest();
            orderRequest.setOutTradeNo(order.getOrderSn());
            orderRequest.setOpenid(openid);
            orderRequest.setBody("订单：" + order.getOrderSn());
            // 元转成分
            int fee = 0;
            BigDecimal actualPrice = order.getActualPrice();
            fee = actualPrice.multiply(new BigDecimal(100)).intValue();
            orderRequest.setTotalFee(fee);
            orderRequest.setSpbillCreateIp(IpUtil.getIpAddr(request));

            result = wxPayService.createOrder(orderRequest);
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseUtil.fail(ORDER_PAY_FAIL, "订单不能支付");
        }

        if (orderService.updateWithOptimisticLocker(order) == 0) {
            return ResponseUtil.updatedDateExpired();
        }
        return ResponseUtil.ok(result);
    }

    /**
     * 微信H5支付
     *
     * @param userId
     * @param orderId
     * @param request
     * @return
     */
    @Transactional
    public Object h5pay(Integer userId, Integer orderId, HttpServletRequest request) {
        if (userId == null) {
            return ResponseUtil.unlogin();
        }
        if (orderId == null) {
            return ResponseUtil.badArgument();
        }

        LitemallOrder order = orderService.findById(userId, orderId);
        if (order == null) {
            return ResponseUtil.badArgumentValue();
        }
        if (!order.getUserId().equals(userId)) {
            return ResponseUtil.badArgumentValue();
        }

        // 检测是否能够取消
        OrderHandleOption handleOption = OrderUtil.build(order);
        if (!handleOption.isPay()) {
            return ResponseUtil.fail(ORDER_INVALID_OPERATION, "订单不能支付");
        }

        WxPayMwebOrderResult result = null;
        try {
            WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest();
            orderRequest.setOutTradeNo(order.getOrderSn());
            orderRequest.setTradeType("MWEB");
            orderRequest.setBody("订单：" + order.getOrderSn());
            // 元转成分
            int fee = 0;
            BigDecimal actualPrice = order.getActualPrice();
            fee = actualPrice.multiply(new BigDecimal(100)).intValue();
            orderRequest.setTotalFee(fee);
            orderRequest.setSpbillCreateIp(IpUtil.getIpAddr(request));

            result = wxPayService.createOrder(orderRequest);

        } catch (Exception e) {
            e.printStackTrace();
        }

        return ResponseUtil.ok(result);
    }

    /**
     * 微信付款成功或失败回调接口
     * <p>
     * 1. 检测当前订单是否是付款状态;
     * 2. 设置订单付款成功状态相关信息;
     * 3. 响应微信商户平台.
     *
     * @param request  请求内容
     * @param response 响应内容
     * @return 操作结果
     */
    @Transactional
    public Object payNotify(HttpServletRequest request, HttpServletResponse response) {
        String xmlResult = null;
        try {
            xmlResult = IOUtils.toString(request.getInputStream(), request.getCharacterEncoding());
        } catch (IOException e) {
            e.printStackTrace();
            return WxPayNotifyResponse.fail(e.getMessage());
        }

        WxPayOrderNotifyResult result = null;
        try {
            result = wxPayService.parseOrderNotifyResult(xmlResult);

            if(!WxPayConstants.ResultCode.SUCCESS.equals(result.getResultCode())){
                logger.error(xmlResult);
                throw new WxPayException("微信通知支付失败！");
            }
            if(!WxPayConstants.ResultCode.SUCCESS.equals(result.getReturnCode())){
                logger.error(xmlResult);
                throw new WxPayException("微信通知支付失败！");
            }
        } catch (WxPayException e) {
            e.printStackTrace();
            return WxPayNotifyResponse.fail(e.getMessage());
        }

        logger.info("处理腾讯支付平台的订单支付");
        logger.info(result);

        String orderSn = result.getOutTradeNo();
        String payId = result.getTransactionId();

        // 分转化成元
        String totalFee = BaseWxPayResult.fenToYuan(result.getTotalFee());
        LitemallOrder order = orderService.findBySn(orderSn);
        if (order == null) {
            return WxPayNotifyResponse.fail("订单不存在 sn=" + orderSn);
        }

        // 检查这个订单是否已经处理过
        if (OrderUtil.hasPayed(order)) {
            return WxPayNotifyResponse.success("订单已经处理成功!");
        }

        // 检查支付订单金额
        if (!totalFee.equals(order.getActualPrice().toString())) {
            return WxPayNotifyResponse.fail(order.getOrderSn() + " : 支付金额不符合 totalFee=" + totalFee);
        }

        order.setPayId(payId);
        order.setPayTime(LocalDateTime.now());
        order.setOrderStatus(OrderUtil.STATUS_WAIT_SEND);
        if (orderService.updateWithOptimisticLocker(order) == 0) {
            return WxPayNotifyResponse.fail("更新数据已失效");
        }


        //TODO 发送邮件和短信通知，这里采用异步发送
        // 订单支付成功以后，会发送短信给用户，以及发送邮件给管理员
//        notifyService.notifyMail("新订单通知", order.toString());
//        // 这里微信的短信平台对参数长度有限制，所以将订单号只截取后6位
//        notifyService.notifySmsTemplateSync(order.getMobile(), NotifyType.PAY_SUCCEED, new String[]{orderSn.substring(8, 14)});

        // 请依据自己的模版消息配置更改参数
        String[] parms = new String[]{
                order.getOrderSn(),
                order.getOrderPrice().toString(),
                DateTimeUtil.getDateTimeDisplayString(order.getAddTime()),
                order.getConsignee(),
                order.getMobile(),
                order.getAddress()
        };

        // 取消订单超时未支付任务
        taskService.removeTask(new OrderUnpaidTask(order.getId()));

        return WxPayNotifyResponse.success("处理成功!");
    }

    /**
     * 订单申请退款
     * <p>
     * 1. 检测当前订单是否能够退款；
     * 2. 设置订单申请退款状态。
     *
     * @param userId 用户ID
     * @param orderId   订单Id
     * @return 订单退款操作结果
     */
    public Object refund(Integer userId, Integer orderId) {
        if (userId == null) {
            return ResponseUtil.unlogin();
        }
        if (orderId == null) {
            return ResponseUtil.badArgument();
        }

        LitemallOrder order = orderService.findById(userId, orderId);
        if (order == null) {
            return ResponseUtil.badArgument();
        }
        if (!order.getUserId().equals(userId)) {
            return ResponseUtil.badArgumentValue();
        }

        OrderHandleOption handleOption = OrderUtil.build(order);
        if (!handleOption.isRefund()) {
            log.error("订单不能申请退款，当前状态：{}", order.getOrderStatus());
            return ResponseUtil.fail(ORDER_INVALID_OPERATION, "订单不能申请退款");
        }

        // 设置订单申请退款状态
        order.setOrderStatus(OrderUtil.STATUS_APPLY_REFUND);
        if (orderService.updateWithOptimisticLocker(order) == 0) {
            return ResponseUtil.updatedDateExpired();
        }

        //TODO 发送邮件和短信通知，这里采用异步发送
        // 有用户申请退款，邮件通知运营人员
//        notifyService.notifyMail("退款申请", order.toString());

        return ResponseUtil.ok();
    }

    public Object confirm(Integer userId, Integer orderId) {

        LitemallOrder order = orderService.findById(userId, orderId);
        if (order == null) {
            throw BusinessException.create("无法查询到该订单！");
        }
        if (!order.getUserId().equals(userId)) {
            throw BusinessException.create("当前用户无法操作该订单！");
        }

        OrderHandleOption handleOption = OrderUtil.build(order);
        if (!handleOption.isConfirm()) {
            throw BusinessException.create("该订单无法确认收货！");
        }

        order.setOrderStatus(OrderUtil.STATUS_COMPLETE);
        order.setConfirmTime(LocalDateTime.now());
        if (orderService.updateWithOptimisticLocker(order) == 0) {
            throw BusinessException.create("确认收货失败，请联系管理员！");
        }
        return ResponseUtil.ok();
    }

    /**
     * 删除订单
     * <p>
     * 1. 检测当前订单是否可以删除；
     * 2. 删除订单。
     *
     * @param userId 用户ID
     * @param body   订单信息，{ orderId：xxx }
     * @return 订单操作结果
     */
    public Object delete(Integer userId, String body) {
        if (userId == null) {
            return ResponseUtil.unlogin();
        }
        Integer orderId = JacksonUtil.parseInteger(body, "orderId");
        if (orderId == null) {
            return ResponseUtil.badArgument();
        }

        LitemallOrder order = orderService.findById(userId, orderId);
        if (order == null) {
            return ResponseUtil.badArgument();
        }
        if (!order.getUserId().equals(userId)) {
            return ResponseUtil.badArgumentValue();
        }

        OrderHandleOption handleOption = OrderUtil.build(order);
        if (!handleOption.isDelete()) {
            return ResponseUtil.fail(ORDER_INVALID_OPERATION, "订单不能删除");
        }

        // 订单order_status没有字段用于标识删除
        // 而是存在专门的delete字段表示是否删除
        orderService.deleteById(orderId);
        // 售后也同时删除
        aftersaleService.deleteByOrderId(userId, orderId);

        return ResponseUtil.ok();
    }

    /**
     * 待评价订单商品信息
     *
     * @param userId  用户ID
     * @param orderId 订单ID
     * @param goodsId 商品ID
     * @return 待评价订单商品信息
     */
    public Object goods(Integer userId, Integer orderId, Integer goodsId) {
        if (userId == null) {
            return ResponseUtil.unlogin();
        }
        LitemallOrder order = orderService.findById(userId, orderId);
        if (order == null) {
            return ResponseUtil.badArgument();
        }

        List<LitemallOrderGoods> orderGoodsList = orderGoodsService.findByOidAndGid(orderId, goodsId);
        int size = orderGoodsList.size();

        Assert.state(size < 2, "存在多个符合条件的订单商品");

        if (size == 0) {
            return ResponseUtil.badArgumentValue();
        }

        LitemallOrderGoods orderGoods = orderGoodsList.get(0);
        return ResponseUtil.ok(orderGoods);
    }

    /**
     * 评价订单商品
     * <p>
     * 确认商品收货或者系统自动确认商品收货后7天内可以评价，过期不能评价。
     *
     * @param userId 用户ID
     * @param body   订单信息，{ orderId：xxx }
     * @return 订单操作结果
     */
    public Object comment(Integer userId, String body) {
        if (userId == null) {
            return ResponseUtil.unlogin();
        }

        Integer orderGoodsId = JacksonUtil.parseInteger(body, "orderGoodsId");
        if (orderGoodsId == null) {
            return ResponseUtil.badArgument();
        }
        LitemallOrderGoods orderGoods = orderGoodsService.findById(orderGoodsId);
        if (orderGoods == null) {
            return ResponseUtil.badArgumentValue();
        }
        Integer orderId = orderGoods.getOrderId();
        LitemallOrder order = orderService.findById(userId, orderId);
        if (order == null) {
            return ResponseUtil.badArgumentValue();
        }
        Short orderStatus = order.getOrderStatus();
        if (!order.getUserId().equals(userId)) {
            return ResponseUtil.fail(ORDER_INVALID, "当前商品不属于用户");
        }
        Integer commentId = orderGoods.getComment();
        if (commentId == -1) {
            return ResponseUtil.fail(ORDER_COMMENT_EXPIRED, "当前商品评价时间已经过期");
        }
        if (commentId != 0) {
            return ResponseUtil.fail(ORDER_COMMENTED, "订单商品已评价");
        }

        String content = JacksonUtil.parseString(body, "content");
        Integer star = JacksonUtil.parseInteger(body, "star");
        if (star == null || star < 0 || star > 5) {
            return ResponseUtil.badArgumentValue();
        }
        Boolean hasPicture = JacksonUtil.parseBoolean(body, "hasPicture");
        List<String> picUrls = JacksonUtil.parseStringList(body, "picUrls");
        if (hasPicture == null || !hasPicture) {
            picUrls = new ArrayList<>(0);
        }

        // 1. 创建评价
        LitemallComment comment = new LitemallComment();
        comment.setUserId(userId);
        comment.setType((byte) 0);
        comment.setValueId(orderGoods.getGoodsId());
        comment.setStar(star.shortValue());
        comment.setContent(content);
        comment.setHasPicture(hasPicture);
        comment.setPicUrls(picUrls.toArray(new String[]{}));
        commentService.save(comment);

        // 2. 更新订单商品的评价列表
        orderGoods.setComment(comment.getId());
        orderGoodsService.updateById(orderGoods);

        // 3. 更新订单中未评价的订单商品可评价数量
        Short commentCount = order.getComments();
        if (commentCount > 0) {
            commentCount--;
        }
        order.setComments(commentCount);
        orderService.updateWithOptimisticLocker(order);

        return ResponseUtil.ok();
    }

    /**
     * 取消订单/退款返还优惠券
     * <br/>
     * @param orderId
     * @return void
     * @author Tyson
     * @date 2020/6/8/0008 1:41
     */
    public void releaseCoupon(Integer orderId) {
        List<LitemallCouponUser> couponUsers = couponUserService.findByOid(orderId);
        for (LitemallCouponUser couponUser: couponUsers) {
            // 优惠券状态设置为可使用
            couponUser.setStatus(CouponUserConstant.STATUS_USABLE);
            couponUser.setUpdateTime(LocalDateTime.now());
            couponUserService.update(couponUser);
        }
    }

    public Object myOrderNum(Integer userId) {
        List<LitemallOrder> orderList = orderService.selectListByUser(userId);
        Map<Short, List<LitemallOrder>> shortListMap = orderList.stream().collect(groupingBy(LitemallOrder::getOrderStatus));
        Map<Short, Integer> numMap = new HashMap<>();
        for (Short key : shortListMap.keySet()) {
            numMap.put(key, shortListMap.get(key).size());
        }
        return ResponseUtil.ok(numMap);
    }

    /**
     * 微信小程序支付
     * @param userId 用户id
     * @param orderId 订单id
     * @return 微信调用支付的参数
     * @throws Exception 异常处理
     */
    public Map<String, Object> wxPay(Integer userId, Integer orderId) throws Exception {
        OurWxPayConfig ourWxPayConfig = new OurWxPayConfig();
        WXPay wxPay = new WXPay(ourWxPayConfig);

        LitemallOrder order = orderService.findById(orderId);
        LitemallUser user = userService.findById(userId);

        Map<String, Object> map;
        // 如果商品类型为1 那就是向钱包充值
        Map<String, String> data = new HashMap<>();
        data.put("body", "素佰佳商品");
        // 商户订单号
        data.put("out_trade_no", order.getOrderSn());
        // 把原来单位是元的数值保存，要存入数据库
        BigDecimal total_fee = order.getActualPrice().multiply(new BigDecimal("100"));
        // 微信那边是分所以乘100
        String fee=total_fee.toString();
        // 获取非小数部分
        data.put("total_fee",  fee.split("\\.")[0]);
        data.put("spbill_create_ip", "127.0.0.1");
        // 回调地址
        data.put("notify_url", notifyUrl);
        // 此处指定支付类型  JSAPI小程序支付  NATIVE扫码支付
        data.put("trade_type", "JSAPI");
        // 微信登录者唯一的openid
        data.put("openid", user.getWeixinOpenid());

        try {
            //这里是封装好的   把东西发给微信
            Map<String, String> resp = wxPay.unifiedOrder(data);
            if ("SUCCESS".equals(resp.get("result_code"))) {
                Map<String, String> reqData=new HashMap<>();
                System.out.println(resp);
                logger.info(resp);
                logger.info("下单成功");
                String appId= ourWxPayConfig.getAppID();
                //返回的要是秒级别
                String timeStamp=""+System.currentTimeMillis()/1000;
                String nonceStr=resp.get("nonce_str");
                String Package=resp.get("prepay_id");
                String signType="MD5";
                map= new HashMap<>();
                map.put("total_fee",total_fee);
                //这里要大写
                map.put("appId",appId);
                map.put("timeStamp",timeStamp);
                map.put("nonceStr",nonceStr);
                map.put("package","prepay_id="+Package);
                map.put("signType",signType);
                //二次签名所用的参数
                reqData.put("appId", ourWxPayConfig.getAppID());
                reqData.put("timeStamp",timeStamp);
                reqData.put("nonceStr",nonceStr);
                reqData.put("package","prepay_id="+Package);
                reqData.put("signType",signType);
                //第二次生成sigh  同样用封装好的
                map.put("sign", WXPayUtil.generateSignature(reqData, ourWxPayConfig.getKey()));
                return map;
            } else {
                throw new RuntimeException("发起支付失败！");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public JsonResponse encore(Integer userId, Integer orderId) {
        List<LitemallOrderGoods> orderGoods = orderGoodsService.queryByOid(orderId);
        orderGoods.forEach(orderGood->{
            LitemallCart cart = CloneUtil.clone(orderGood, LitemallCart.class);
            cart.setUserId(userId);
            cart.setChecked(true);
            LitemallCart litemallCart = cartService.queryExist(orderGood.getGoodsId(), userId);
            if (!Objects.isNull(litemallCart)) {
                litemallCart.setNumber((short)(litemallCart.getNumber() + 1));
                cartService.updateById(litemallCart);
                return;
            }
            cartService.add(cart);
        });
        return JsonResponse.ok("添加成功");
    }

    public Object cancelRefund(Integer userId, Integer orderId) {
        if (userId == null) {
            return ResponseUtil.unlogin();
        }

        LitemallOrder order = orderService.findById(userId, orderId);
        if (order == null) {
            return ResponseUtil.badArgumentValue();
        }
        if (!order.getOrderStatus().equals(OrderUtil.STATUS_APPLY_REFUND)) {
            log.error("不能取消退款，状态是：{}", order.getOrderStatus());
            return JsonResponse.error("无法取消退款");
        }
        order.setOrderStatus(OrderUtil.STATUS_WAIT_SEND);
        if (orderService.updateWithOptimisticLocker(order) == 0) {
            return ResponseUtil.updatedDateExpired();
        }
        return ResponseUtil.ok();
    }
}
